/** 
  ******************************************************************************
  * @file    /User/main.c 
  * @author  Zheyu Zhou, Zhenyu Yang, HSiang HSu
  * @version V0.1
  * @date    2024年01月16日 V0.1 ：初始版本
  *          2024年08月29日 V0.2 ：规范化模板
  * @brief   模板主函数
  ******************************************************************************
**/ 

/* 1.Include -------------------------------------------------------------------*/
#include <stdint.h>
#include "main.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
SUART suart1 = {0};                                                      // 串口1数据
SDATA sdat = {0};

/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static unsigned int LL_CRC_Calculate(unsigned int *buf, unsigned int len);
static void DataConvert(SDATA *ldat);
static void SendDataUART(unsigned char *buf, unsigned short len);
static void SendDataUSB(unsigned char *buf, unsigned int len);
/* Private user code ---------------------------------------------------------*/

/**
* @brief  main                 主函数
* @param  None
* @retval int                  返回参数
*/
int main(void)
{
    unsigned char val;
    char str[] = "test\n";

    /* Configure the system clock */
    SystemClock_Config();

    // 板级支持包
    BSP_Init();

    // TinyUSB
    tud_init(0);

    // 主循环
    while (1)
    {
        // DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
        // t1 = DWT->CYCCNT;
        // LL_mDelay(10);
        // t2 = DWT->CYCCNT;
        // dt = t2 - t1;
        LED1_Toggle; 
        DataConvert(&sdat);
        SendDataUART(sdat.buf, sdat.len);
        SendDataUSB(sdat.buf, sdat.len);
        IO_OUT(1);
        DelayMS(500);
        IO_OUT(0);
        val = IO_IN;
        DelayUS(500000);
    }

}

/**
  * @brief System Clock Configuration
  * @retval None
  */
static void SystemClock_Config(void)
{

    /* Enable HSE oscillator */
    LL_RCC_HSE_Enable();
    while(LL_RCC_HSE_IsReady() != 1)
    {
    };

    /* Set FLASH latency */
    LL_FLASH_SetLatency(LL_FLASH_LATENCY_5);

    /* Main PLL configuration and activation */
    LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_8, 336, LL_RCC_PLLP_DIV_2);
    LL_RCC_PLL_Enable();
    while(LL_RCC_PLL_IsReady() != 1)
    {
    };

    /* Sysclk activation on the main PLL */
    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
    while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
    {
    };

    /* Set APB1 & APB2 prescaler */
    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_4);
    LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2);

        /* 配置PLLQ用于USB OTG FS时钟源 */
    LL_RCC_PLL_ConfigDomain_48M(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_8, 336, LL_RCC_PLLQ_DIV_7);
    while(LL_RCC_PLL_IsReady() != 1)
    {
    };
    /* Set systick to 1ms */
    SysTick_Config(168000000 / 1000);

    /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
    SystemCoreClock = 168000000;

}

/**
* @brief  LL_CRC_Calculate     硬件CRC校验计算
* @param  buf    uint32        数据缓存
*         len    uint32        数据长度
* @retval uint32               返回计算结果
*/
static unsigned int LL_CRC_Calculate(unsigned int *buf, unsigned int len)
{
    unsigned int i;

    LL_CRC_ResetCRCCalculationUnit(CRC);
    for (i = 0; i < len; i++)
    {
        LL_CRC_FeedData32(CRC, __RBIT(buf[i]));
    }
    
    return __RBIT(LL_CRC_ReadData32(CRC)) ^ 0xFFFFFFFF;
}

/**
* @brief  DataConvert          数据转换
* @param  SDATA    结构体       输入数据
* @retval None                    
*/
static void DataConvert(SDATA *ldat)
{
    union FL2UCH fdat;
    unsigned char i;
    unsigned char crc = 0;
    
    // 字长归0
    ldat->len = 0;

    // 帧头
    ldat->buf[ldat->len] = 0x55; ldat->len++;
    ldat->buf[ldat->len] = 0x55; ldat->len++;

    // 帧号
    ldat->buf[ldat->len] = 0x00; ldat->len++;

    // 数据
    fdat.f = 13.1f;
    ldat->buf[ldat->len] = fdat.c[0]; ldat->len++;
    ldat->buf[ldat->len] = fdat.c[1]; ldat->len++;
    ldat->buf[ldat->len] = fdat.c[2]; ldat->len++;
    ldat->buf[ldat->len] = fdat.c[3]; ldat->len++;
    // ...

    // CRC 校验，32位，从第三个字节开始，末尾1表示1*4字节，总共4个字节
    *((uint32_t *)&ldat->buf[ldat->len]) = LL_CRC_Calculate((uint32_t *)&ldat->buf[3], 1);
    ldat->len += 4;
}

/**
* @brief  SendDataUSB          USB数据发送
* @param  buf    uint8         数据缓存
*         len    uint32        数据长度
* @retval None                    
*/
static void SendDataUSB(unsigned char *buf, unsigned int len)
{
    tud_cdc_n_write(0, buf, len);
    tud_cdc_n_write_flush(0);
}

/**
* @brief  SendDataUSB       USB数据发送
* @param  buf    uint8      数据缓存
*         len    uint32     数据长度
* @retval None                    
*/
static void SendDataUART(unsigned char *buf, unsigned short len)
{

    // Enable DMA Channel Rx
    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_2);

    // Enable DMA Channel Tx
    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_7);

    suart1.txlen = len;
    memcpy(suart1.txbuf, buf, suart1.txlen);
    LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_7,
                        (uint32_t)suart1.txbuf,
                        LL_USART_DMA_GetRegAddr(USART1),
                        LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_7));
    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_7, suart1.txlen);

    // /* Enable DMA RX Interrupt */ 需要测试
    // LL_USART_EnableDMAReq_RX(USART1);

    // /* Enable DMA TX Interrupt */
    // LL_USART_EnableDMAReq_TX(USART1);

    /* Enable DMA Channel Rx */
    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);

    // Enable DMA Channel Tx
    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_7);
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/* end------------------------------------------------------------------------*/

